﻿//
// Copyright (c) 2010 Alex Forster.
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of
// the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// 
// ZeroMQ is a trademark of iMatix Corporation.
// 

using System;
using System.Runtime.InteropServices;

namespace ZeroMQ
{
	public static class Interop
	{
		/// <summary>Determine the version of the dynamically loaded ZeroMQ library</summary>
		[DllImport( "libzmq" )]
		public static extern void zmq_version( IntPtr major, IntPtr minor, IntPtr patch );

		public const Int32 ZMQ_HAUSNUMERO = 156384712;

		// note- we're guessing the Posix error codes; these values aren't standardized

		public static readonly Int32 ENOTSUP = Environment.OSVersion.Platform == PlatformID.Unix ? 134 : ZMQ_HAUSNUMERO + 1;

		public static readonly Int32 EPROTONOSUPPORT = Environment.OSVersion.Platform == PlatformID.Unix ? 123 : ZMQ_HAUSNUMERO + 2;

		public static readonly Int32 ENOBUFS = Environment.OSVersion.Platform == PlatformID.Unix ? 105 : ZMQ_HAUSNUMERO + 3;

		public static readonly Int32 ENETDOWN = Environment.OSVersion.Platform == PlatformID.Unix ? 115 : ZMQ_HAUSNUMERO + 4;

		public static readonly Int32 EADDRINUSE = Environment.OSVersion.Platform == PlatformID.Unix ? 112 : ZMQ_HAUSNUMERO + 5;

		public static readonly Int32 EADDRNOTAVAIL = Environment.OSVersion.Platform == PlatformID.Unix ? 125 : ZMQ_HAUSNUMERO + 6;

		public static readonly Int32 ECONNREFUSED = Environment.OSVersion.Platform == PlatformID.Unix ? 111 : ZMQ_HAUSNUMERO + 7;

		public static readonly Int32 EINPROGRESS = Environment.OSVersion.Platform == PlatformID.Unix ? 119 : ZMQ_HAUSNUMERO + 8;

		public static readonly Int32 ENOTSOCK = Environment.OSVersion.Platform == PlatformID.Unix ? 119 : ZMQ_HAUSNUMERO + 9;

		public const Int32 EFSM = ZMQ_HAUSNUMERO + 51;

		public const Int32 ENOCOMPATPROTO = ZMQ_HAUSNUMERO + 52;

		public const Int32 ETERM = ZMQ_HAUSNUMERO + 53;

		public const Int32 EMTHREAD = ZMQ_HAUSNUMERO + 54;

		public const Int32 EINTR = 4;

		public const Int32 EBADF = 9;

		public const Int32 EAGAIN = 11;

		public const Int32 ENOMEM = 12;

		public const Int32 EFAULT = 14;

		public const Int32 ENODEV = 19;

		public const Int32 EINVAL = 22;

		public const Int32 EMFILE = 24;

		public const Int32 EPIPE = 32;

		public const Int32 ENAMETOOLONG = 36;

		public const Int32 ECONNABORTED = 103;

		public const Int32 ECONNRESET = 104;

		public const Int32 ETIMEDOUT = 110;

		public const Int32 EHOSTUNREACH = 113;

		/// <summary>Retrieve the value of "errno" for the calling thread</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_errno();

		/// <summary>Retrieve the error message string for a specific "errno" value</summary>
		[DllImport( "libzmq" )]
		public static extern IntPtr zmq_strerror( Int32 errnum );

		/// <summary>Delimiter message type</summary>
		public const Int32 ZMQ_DELIMITER = 31;

		/// <summary>Very Small Message message type</summary>
		public const Int32 ZMQ_VSM = 32;

		/// <summary>More message flag</summary>
		public const Int32 ZMQ_MSG_MORE = 1;

		/// <summary>Shared message flag</summary>
		public const Int32 ZMQ_MSG_SHARED = 128;

		/// <summary>Shared & More combined message flag</summary>
		public const Int32 ZMQ_MSG_MASK = 129;

		/// <summary>Allocate internal resources for a message</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_msg_init( IntPtr msg );

		/// <summary>Allocate internal resources for a message of a specific size</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_msg_init_size( IntPtr msg, Int32 size );

		[UnmanagedFunctionPointer( CallingConvention.Cdecl )]
		public delegate void zmq_free_fn( IntPtr data, IntPtr hint );

		/// <summary>Allocate internal resources for a message of a specific size and with the specified content</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_msg_init_data( IntPtr msg, IntPtr data, Int32 size, zmq_free_fn ffn, IntPtr hint );

		/// <summary>Deallocate internal resources for a message</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_msg_close( IntPtr msg );

		/// <summary>Move the contents of one message into another (pre-initialized) message, emptying the original</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_msg_move( IntPtr dest, IntPtr src );

		/// <summary>Copy the contents of one message into another (pre-initialized) message</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_msg_copy( IntPtr dest, IntPtr src );

		/// <summary>Retrieve a message's data pointer</summary>
		[DllImport( "libzmq" )]
		public static extern IntPtr zmq_msg_data( IntPtr msg );

		/// <summary>Retrieve a message's size</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_msg_size( IntPtr msg );

		/// <summary>Allocate a ZeroMQ context with a specific IO threadpool size</summary>
		[DllImport( "libzmq" )]
		public static extern IntPtr zmq_init( Int32 io_threads );

		/// <summary>Deallocate a ZeroMQ context</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_term( IntPtr context );

		/// <summary>Pair socket type</summary>
		public const Int32 ZMQ_PAIR = 0;

		/// <summary>Publish-only socket type</summary>
		public const Int32 ZMQ_PUB = 1;

		/// <summary>Subscribe-only socket type</summary>
		public const Int32 ZMQ_SUB = 2;

		/// <summary>Request socket type</summary>
		public const Int32 ZMQ_REQ = 3;

		/// <summary>Reply socket type</summary>
		public const Int32 ZMQ_REP = 4;

		/// <summary>Dealer socket type</summary>
		public const Int32 ZMQ_DEALER = 5;

		[Obsolete]
		public const Int32 ZMQ_XREQ = Interop.ZMQ_DEALER;

		/// <summary>Router socket type</summary>
		public const Int32 ZMQ_ROUTER = 6;

		[Obsolete]
		public const Int32 ZMQ_XREP = Interop.ZMQ_ROUTER;

		/// <summary>Pull-only socket type</summary>
		public const Int32 ZMQ_PULL = 7;

		[Obsolete]
		public const Int32 ZMQ_UPSTREAM = Interop.ZMQ_PULL;

		/// <summary>Push-only socket type</summary>
		public const Int32 ZMQ_PUSH = 8;

		[Obsolete]
		public const Int32 ZMQ_DOWNSTREAM = Interop.ZMQ_PUSH;

		/// <summary>Extended publish-only socket type</summary>
		public const Int32 ZMQ_XPUB = 9;

		/// <summary>Extended subscribe-only socket type</summary>
		public const Int32 ZMQ_XSUB = 10;

		/// <summary>High watermark socket option</summary>
		public const Int32 ZMQ_HWM = 1;

		/// <summary>Swap size socket option</summary>
		public const Int32 ZMQ_SWAP = 3;

		/// <summary>I/O thread affinity socket option</summary>
		public const Int32 ZMQ_AFFINITY = 4;

		/// <summary>Context identity socket option</summary>
		public const Int32 ZMQ_IDENTITY = 5;

		/// <summary>Filter subscription socket option</summary>
		public const Int32 ZMQ_SUBSCRIBE = 6;

		/// <summary>Filter unsubscription socket option</summary>
		public const Int32 ZMQ_UNSUBSCRIBE = 7;

		/// <summary>Rate-limit socket option</summary>
		public const Int32 ZMQ_RATE = 8;

		/// <summary>Recovery interval socket option</summary>
		public const Int32 ZMQ_RECOVERY_IVL = 9;

		/// <summary>Mulitcast loopback socket option</summary>
		public const Int32 ZMQ_MCAST_LOOP = 10;

		/// <summary>Send buffer size socket option</summary>
		public const Int32 ZMQ_SNDBUF = 11;

		/// <summary>Receive buffer size socket option</summary>
		public const Int32 ZMQ_RCVBUF = 12;

		/// <summary>Receive more socket option</summary>
		public const Int32 ZMQ_RCVMORE = 13;

		/// <summary>File descriptor socket option</summary>
		public const Int32 ZMQ_FD = 14;

		/// <summary>Event state socket option</summary>
		public const Int32 ZMQ_EVENTS = 15;

		/// <summary>Native file descriptor socket option</summary>
		public const Int32 ZMQ_TYPE = 16;

		/// <summary>Shutdown linger period socket option</summary>
		public const Int32 ZMQ_LINGER = 17;

		/// <summary>Reconnection-attempt interval socket option</summary>
		public const Int32 ZMQ_RECONNECT_IVL = 18;

		/// <summary>Message backlog socket option</summary>
		public const Int32 ZMQ_BACKLOG = 19;

		/// <summary>Multicast recovery interval (milliseconds) socket option</summary>
		public const Int32 ZMQ_RECOVERY_IVL_MSEC = 20;

		/// <summary>Max reconnection-attempt interval socket option</summary>
		public const Int32 ZMQ_RECONNECT_IVL_MAX = 21;

		/// <summary>No-block send flag</summary>
		public const Int32 ZMQ_NOBLOCK = 1;

		/// <summary>Send-more send flag</summary>
		public const Int32 ZMQ_SNDMORE = 2;

		/// <summary>Allocate internal resources for a ZeroMQ socket of a specific type</summary>
		[DllImport( "libzmq" )]
		public static extern IntPtr zmq_socket( IntPtr context, Int32 type );

		/// <summary>Deallocate internal resources for a ZeroMQ socket</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_close( IntPtr socket );

		/// <summary>Set an option for a ZeroMQ socket</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_setsockopt( IntPtr socket, Int32 option, IntPtr optval, Int32 optvallen );

		/// <summary>Get an option for a ZeroMQ socket</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_getsockopt( IntPtr socket, Int32 option, IntPtr optval, IntPtr optvallen );

		/// <summary>Bind a ZeroMQ socket to a specific address</summary>
		[DllImport( "libzmq", CharSet = CharSet.Ansi )]
		public static extern Int32 zmq_bind( IntPtr socket, String addr );

		/// <summary>Connect a ZeroMQ socket to a specific address</summary>
		[DllImport( "libzmq", CharSet = CharSet.Ansi )]
		public static extern Int32 zmq_connect( IntPtr socket, String addr );

		/// <summary>Send a message on a ZeroMQ socket</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_send( IntPtr socket, IntPtr msg, Int32 flags );

		/// <summary>Receive the next message on a ZeroMQ socket</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_recv( IntPtr socket, IntPtr msg, Int32 flags );

		/// <summary>Poll for data received from the referenced sockets</summary>
		public const Int32 ZMQ_POLLIN = 1;

		/// <summary>Poll for data sent on the referenced sockets</summary>
		public const Int32 ZMQ_POLLOUT = 2;

		/// <summary>Poll for errors on the referenced sockets</summary>
		public const Int32 ZMQ_POLLERR = 4;

		/// <summary>Represents a socket and its relevant events</summary>
		[StructLayout( LayoutKind.Sequential )]
		public struct zmq_pollitem_t
		{
			public IntPtr socket;

			public IntPtr fd;

			public Int16 events;

			public Int16 revents;
		}

		/// <summary>Block on the current thread until one of the referenced sockets raise an event or a timeout expires</summary>
		[DllImport( "libzmq" )]
		public static extern Int32 zmq_poll( [In] [Out] zmq_pollitem_t[] items, Int32 nitems, Int32 timeout );
	}
}
